#ifndef __JUEGO_H__
#define __JUEGO_H__

//Servicios usados
#include "../aed2/aed2.h"
#include "tablero.h"
#include "diccAcotado.h"
#include "diccTrie.h"
#include "multconjAcotado.h"
#include "diccAcotado.h"

namespace aed2{
	//Renombres
	//typedef unsigned int Casilla; //No hace falta, ya está definido en tablero.h
	//typedef unsigned int Continente; //No hace falta, ya está definido en tablero.h
	typedef unsigned int Jugador;
	typedef unsigned int Mision;
	typedef String Movimiento;


	class Juego {

	  private:

		// ESTRUCTURA DE REPRESENTACIÓN
		
		struct DescriptorJugador {
			Nat 	    fichas;
			Nat 	    fichasAgregadas;
			Continente 	mision;
			ConjAcotado casillasDominadas;
			Nat 		cantDomMision;	  
			
			DescriptorJugador (Nat fchs, Nat fchsAgr, Continente  mis, ConjAcotado casDom, Nat cantDomMis)
				: fichas(fchs), fichasAgregadas(fchsAgr), mision(mis), casillasDominadas(casDom), cantDomMision(cantDomMis) {
			}
		};
		
		const Tablero<Movimiento> & tablero;
		DiccTrie<DiccAcotado<Conj<Casilla> > > origenesPorCasilla;
		DiccAcotado<DescriptorJugador> jugadores;
		ConjAcotado jugadoresConFichas;
		DiccAcotado<MultConjAcotado> fichasPorCasilla;
		
		  
		// OPERACIONES PRIVADAS
		/**
		 * Constructor por defecto (OCULTO)
		 * 
		 * PRE : Ninguna.
		 * POST: Un juego vacío.
		 * 	
		 * @Parámetros: Ninguno.
		 * 
		 * @Devuelve: Una instancia vacía del juego.
		 * 	
		 */
		Juego();

		/**
		 * Suma una cantidad determinada de fichas a un jugador en la casilla especificada
		 *
		 * PRE : El jugador pertenece al juego, la casilla pertenece al tablero del juego y cant es mayor a cero.
		 * POST: Se sumó la cantidad de fichas requerida en la casilla al jugador.
		 * 	
		 * @Parámetros:
		 * 	jug  : Jugador al cual sumar las fichas
		 * 	cas  : Casilla donde se sumarán las fichas
		 * 	cant : Cantidad de fichas a sumar.
		 * 	
		 * @Devuelve: La cantidad resultante de fichas del jugador.
		 */
		Nat SumarFichas(Jugador jug, Casilla cas, Nat cant);

		
		/**
		 * Resta una cantidad determinada de fichas a un jugador en la casilla especificada
		 *
		 * PRE : El jugador pertenece al juego, la casilla pertenece al tablero del juego y no está vacía, y cant es mayor a cero.
		 * POST: Se restó la cantidad de fichas requerida en la casilla al jugador.
		 * 	
		 * @Parámetros:
		 * 	jug  : Jugador al cual restar las fichas
		 * 	cas  : Casilla donde se restarán las fichas
		 * 	cant : Cantidad de fichas a restar.
		 * 	
		 * @Devuelve: La cantidad de fichas que efectivamente se pudo restar.
		 */
		Nat RestarFichas(Jugador jug, Casilla cas, Nat cant);
		
		
		/**
		* Genera un diccionario que contiene los movimientos y el conjunto de casillas que llegan a una casilla determinada
		* a través del movimiento.
		* PRE : Ninguna.
		* POST: Se actualizó el atributo origenesPorCasilla del Juego.
		* 	
		* @Parámetros:
		* 	Ninguno.
		* 	
		* @Devuelve: Nada.
		*/
		void OrigenesPorCasilla();
	  
	  public:

		/**
		 * Constructor Inicial
		 *
		 * PRE : Los vectores de casillas iniciales y misión no deben estar vacíos y tienen que tener la misma longitud.
		 * POST: Se generó un juego, con jugadores con misión y casilla inicial de acuerdo a lo indicado en los vectores.
		 * 	
		 * @Parámetros:
		 * 	tb : Tablero del juego
		 * 	cs : Casillas iniciales de cada jugador.
		 * 	ms : Misión de cada jugador
		 * 	
		 * @Devuelve: Una instancia válida de Juego
		 */

		Juego(const Tablero<Movimiento> & tb, const Vector<Casilla> & cs, const Vector<Mision> & ms);
		
		/**
		 * Agrega una ficha a un jugador determinado en una casilla.
		 *
		 * PRE : El jugador existe en el juego y no está eliminado y la casilla está vacía o dominada por el jugador.
		 * POST: Se agregó una ficha al jugador en la casilla indicada.
		 * 	
		 * @Parámetros:
		 * 	jug : Jugador al cual agregar la ficha
		 * 	cas : Casilla a la cual agregar la ficha.
		 * 	
		 * @Devuelve: Nada.
		 */
		void AgregarFicha(Jugador jug, Casilla cas);
		
		/**
		 * Mueve una cantidad de fichas determinada desde todas las casillas donde
		 * el jugador es dominante y tienen un movimiento de salida determinado.
		 *
		 * PRE : El jugador existe y no está eliminado.
		 * POST: Se agregó una ficha al jugador en la casilla indicada.
		 * 	
		 * @Parámetros:
		 * 	jug  : Jugador que realiza el movimiento.
		 * 	mov  : Movimiento a partir del cual mover las fichas.
		 * 	cant : Cantidad de fichas a mover.
		 * 	
		 * @Devuelve: Nada.
		 */
		void Mover(Jugador jug, Movimiento mov, Nat cant);
		

		/**
		 * Devuelve el tablero del juego
		 *
		 * PRE : Ninguna.
		 * POST: El resultado es el tablero del juego.
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: El tablero del juego.
		 */
		const Tablero<Movimiento> & TableroDelJuego() const;

		/**
		 * Devuelve un iterador al conjunto de los jugadores del juego
		 *
		 * PRE : Ninguna.
		 * POST: El resultado es un iterador no modificable el conjunto de los jugadores del juego
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: Un iterador al conjunto de los jugadores del juego
		 */
		ConjAcotado::const_Iterador Jugadores() const;
		
		/**
		 * Devuelve un iterador al multiconjunto con las fichas de la casilla especificada
		 *
		 * PRE : La casilla pertenece al tablero.
		 * POST: El resultado es un iterador al multiconjunto de las fichas de la casilla
		 * 	
		 * @Parámetros:
		 *	cas : casilla para la cual se piden las fichas
		 * 	
		 * @Devuelve: El iterador al multiconjunto de las fichas de la casilla indicada
		 */
		MultConjAcotado::const_Iterador Fichas(Casilla cas) const;

		/**
		 * Devuelve la misión del jugador especificado
		 *
		 * PRE : El jugador pertenece al juego.
		 * POST: El resultado es la misión del jugador
		 * 	
		 * @Parámetros:
		 *	jug : el jugador para el cual se busca la misión
		 * 	
		 * @Devuelve: La misión del jugador especificado
		 */
		Mision MisionDe(Jugador jug) const;

		/**
		 * Devuelve la cantidad de fichas agregadas por un jugador en todo el juego
		 *
		 * PRE : El jugador pertenece al juego.
		 * POST: El resultado es la cantidad de fichas agregadas por el jugador.
		 * 	
		 * @Parámetros:
		 *	jug : el jugador para el cual se desea saber la cantidad de fichas agregadas
		 * 	
		 * @Devuelve: La cantidad de fichas agregadas por el jugador especificado
		 */
		Nat FichasAgregadas(Jugador jug) const;

		
		/**
		 * Indica si la casilla especificada se encuentra dominada
		 *
		 * PRE : La casilla pertenece al tablero del juego
		 * POST: El resultado es el bool sobre si la casilla está dominada
		 * 	
		 * @Parámetros:
		 *	cas : La casilla para la cual se quiere saber si está dominada
		 * 	
		 * @Devuelve: El bool indicando si la casilla está dominada.
		 */
		bool Dominada(Casilla cas) const;

		
		/**
		 * Indica si la casilla especificada está vacía
		 *
		 * PRE : La casilla pertenece al tablero del juego
		 * POST: El resultado es el bool sobre si la casilla está vacía
		 * 	
		 * @Parámetros:
		 *	cas : La casilla para la cual se quiere saber si está vacía
		 * 	
		 * @Devuelve: El bool indicando si la casilla está vacía.
		 */
		bool Vacia(Casilla cas) const;

		
		/**
		 * Indica si la casilla especificada está disputada
		 *
		 * PRE : La casilla pertenece al tablero del juego
		 * POST: El resultado es el bool sobre si la casilla está disputada
		 * 	
		 * @Parámetros:
		 *	cas : La casilla para la cual se quiere saber si está disputada
		 * 	
		 * @Devuelve: El bool indicando si la casilla está disputada.
		 */
		bool Disputada(Casilla cas) const;
		

		/**
		 * Devuelve un iterador al conjunto de jugadores que disputan la casilla especificada
		 *
		 * PRE : La casilla pertenece al tablero del juego y está disputada.
		 * POST: El resultado es un iterador al conjunto de los jugadores que disputan la casilla
		 * 	
		 * @Parámetros:
		 *	cas : La casilla para la cual se quiere obtener los disputantes
		 * 	
		 * @Devuelve: Un iterador al conjunto de los disputantes de la casilla especificada
		 */
		MultConjAcotado::const_Iterador_Unicos Disputan(Casilla cas) const;
		
		
		/**
		 * Devuelve el jugador que domina la casilla especificada
		 *
		 * PRE : La casilla pertenece al tablero del juego y está dominada.
		 * POST: El resultado es el el jugador que domina la casilla.
		 * 	
		 * @Parámetros:
		 *	cas : La casilla para la cual se quiere obtener el dominador
		 * 	
		 * @Devuelve: El dominador de la casilla
		 */
		Jugador  Dominador(Casilla cas) const;

		
		/**
		 * Devuelve un iterador no modificable al conjunto de casillas dominadas por el jugador especificado
		 *
		 * PRE : El jugador pertenece al juego
		 * POST: El resultado es un iterador al conjunto de las casillas dominadas por el jugador
		 * 	
		 * @Parámetros:
		 *	jug : El jugador para el cual se quieren obtener las casillas dominadas
		 * 	
		 * @Devuelve: Un iterador no modificable sobre conjunto de casillas dominadas por el jugador
		 */
		ConjAcotado::const_Iterador  Dominadas(Jugador jug) const;

		
		/**
		 * Devuelve la cantidad de casillas que le falta dominar al jugador especificado para cumplir su misión
		 *
		 * PRE : El jugador pertenece al juego
		 * POST: El resultado es la cantidad de casillas que le falta dominar al jugador
		 * 	
		 * @Parámetros:
		 *	jug : El jugador para el cual se quieren obtener la cantidad de casillas por dominar
		 * 	
		 * @Devuelve: El cantidad de por dominadar del jugador
		 */
		Nat  PorDominar(Jugador jug) const;

		
		/**
		 * Indica si el jugador especificado cumplió su misión
		 *
		 * PRE : El jugador pertenece al juego
		 * POST: El resultado es el bool acerca de si el jugador cumplió su misión
		 * 	
		 * @Parámetros:
		 *	jug : El jugador para el cual se quieren saber si cumplió su misión
		 * 	
		 * @Devuelve: Un bool acerca de si el jugador cumplió su misión
		 */
		bool  MisionCumplida(Jugador jug) const;

		
		/**
		 * Indica si el jugador especificado tiene fichas en el juego
		 *
		 * PRE : El jugador pertenece al juego
		 * POST: El resultado es bool acerca de si el jugador tiene fichas
		 * 	
		 * @Parámetros:
		 *	jug : El jugador para el cual se desea saber si tiene fichas
		 * 	
		 * @Devuelve: Un bool acerca de si el jugador tiene fichas
		 */
		bool  TieneFichas(Jugador jug) const;

		
		/**
		 * Devuelve un iterador no modificable sobre el conjunto de jugadores con fichas del juego
		 *
		 * PRE : Ninguna
		 * POST: El resultado es un iterador sobre el conjunto de jugadores con fichas del juego
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: Un iterador no modificable sobre el conjunto de jugadores que tienen fichas.
		 */
		ConjAcotado::const_Iterador  ConFichas() const;

		/**
		 * Retorna la cantidad de jugadores que tienen fichas.
		 *
		 * PRE : Ninguna
		 * POST: Ninguna
		 *
		 * @Parámetros: Ninguno.
		 *
		 * @Devuelve: La cantidad
		 */
		Nat CantidadConFichas() const;

		
		/**
		 * Devuelve el conjunto de jugadores eliminados del juego
		 *
		 * PRE : El juego no está finalizado
		 * POST: El resultado es el conjunto de jugadores eliminados del juego
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: Un conjunto con los jugadores eliminados del juego, que puede estar vacío.
		 */
		ConjAcotado  Eliminados() const;
		

		/**
		 * Devuelve el conjunto de jugadores que cumplieron su misión
		 *
		 * PRE : Ninguna
		 * POST: El resultado es el conjunto de jugadores que cumplieron su misión
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: Un conjunto con los jugadores que cumplieron su misión, que puede estar vacío.
		 */
		//MMS: Cambiado a ConjAcotado (estaba Conj<Jugador>) para unificar los tipos de iteradores
		ConjAcotado CumplieronMision() const;
		
		
		/**
		 * Devuelve un iterador no modificable al conjunto de jugadores que ganaron el juego
		 *
		 * PRE : El juego está finalizado
		 * POST: El resultado es un iterador al conjunto de jugadores que ganaron el juego
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: Un iterador no modificable al conjunto con los jugadores que ganaron el juego
		 */
		//MMS: Cambiado a ConjAcotado, estaba Conj<Jugador>, pero no podemos devolver eso por el momento
		ConjAcotado  Ganadores() const;
		
		
		/**
		 * Indica si el juego finalizó
		 *
		 * PRE : Ninguna.
		 * POST: El resultado es el bool sobre si el juego finalizó
		 * 	
		 * @Parámetros: Ninguno.
		 * 	
		 * @Devuelve: El bool indicando si el juego finalizó.
		 */
		bool Finalizado() const;

		
		/**
		 * Devuelve el conjunto de casillas que pertenecen al tablero del juego.
		 *
		 * PRE : Ninguna.
		 * POST: El resultado es el conjunto de casillas del tablero del juego
		 * 	
		 * @Parámetros: Ninguno.
		 * 
		 * @Devuelve: Un conjunto de casillas con todas aquellas que pertenecen al tablero del juego.
		 */
		Conj<Casilla> Casillas() const;

		
		/**
		 * Devuelve el conjunto de continentes que pertenecen al tablero del juego.
		 *
		 * PRE : Ninguna.
		 * POST: El resultado es el conjunto de continentes del tablero del juego
		 * 	
		 * @Parámetros: Ninguno.
		 * 
		 * @Devuelve: Un conjunto de continentes con todos aquellos que pertenecen al tablero del juego.
		 */
		Conj<Continente> Continentes() const;


		/**
		 * Indica si el jugador especificado puede agregar fichas en la casilla definida
		 *
		 * PRE : El jugador pertenece al juego y la casilla pertenece al tablero del juego.
		 * POST: El resultado es el bool sobre si el jugador puede agregar fichas en la casilla
		 * 	
		 * @Parámetros:
		 *	jug : El jugador para el cual se desea saber si puede agregar fichas
		 *	cas : La casilla a evaluar si el jugador puede agregar fichas
		 * 	
		 * @Devuelve: El bool indicando si el jugador puede agregar fichas en la casilla
		 */
		bool PuedeAgregar(Jugador jug, Casilla cas) const;

	};

}

#endif /* __JUEGO_H__ */
